package xgotool

import (
	"fmt"
	"log"
	"net"
	"os"
	"strings"
	"time"

	"gitee.com/xiaoyutab/xgotool/xerror"
	"golang.org/x/crypto/ssh"
)

// 连接的配置
type ClientConfig struct {
	Host     string      //ip
	Port     int         // 端口
	Username string      //用户名
	Password string      //密码
	IsPK     bool        // 是否是证书【如果是证书的话，password项填写证书位置】
	Client   *ssh.Client //ssh client
}

// 创建连接
func sshClient(cliConf *ClientConfig) error {
	if cliConf.Username == "" {
		return xerror.New("SSH: 登陆账号不允许为空")
	}
	if cliConf.Password == "" {
		return xerror.New("SSH: 登陆密码不允许为空")
	}
	if strings.LastIndex(cliConf.Username, "*") > 0 {
		return xerror.New("SSH: 登陆账号不允许存在 *")
	}
	if cliConf.Port == 0 {
		cliConf.Port = 22
	}
	config := ssh.ClientConfig{
		User: cliConf.Username,
		Auth: []ssh.AuthMethod{ssh.Password(cliConf.Password)},
		HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
			return nil
		},
		Timeout: 60 * time.Second, // 超时时间设置为60秒
	}
	if cliConf.IsPK {
		config.Auth = []ssh.AuthMethod{publicKeyAuthFunc(cliConf.Password)}
	}
	addr := fmt.Sprintf("%s:%d", cliConf.Host, cliConf.Port)

	//获取client
	client, err := ssh.Dial("tcp", addr, &config)
	if err != nil {
		return err
	}
	cliConf.Client = client
	return nil
}

// 运行Shell并获取输出内容
//
//	shell	待运行的命令
func SshExec(cliConf *ClientConfig, shell string) (string, error) {
	if cliConf.Client == nil {
		err := sshClient(cliConf)
		if err != nil {
			return "", err
		}
	}
	//获取session，这个session是用来远程执行操作的
	session, err := cliConf.Client.NewSession()
	if err != nil {
		return "", err
	}
	// 执行命令
	output, err := session.CombinedOutput(shell)
	if err != nil {
		return "", err
	}
	return string(output), nil
}

// 根据KPATH进行证书签名
//
//	kPath	私钥证书路径
func publicKeyAuthFunc(kPath string) ssh.AuthMethod {
	key, err := os.ReadFile(kPath)
	if err != nil {
		log.Fatal("ssh 密钥文件读取失败", err)
	}
	signer, err := ssh.ParsePrivateKey(key)
	if err != nil {
		log.Fatal("ssh 关键签名失败", err)
	}
	return ssh.PublicKeys(signer)
}
